package org.jsola.contract.service.impl;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsola.common.DateKit;
import org.jsola.common.DateKit8;
import org.jsola.contract.constant.AccountType;
import org.jsola.contract.constant.ContractConstants;
import org.jsola.contract.dao.IContractDAO;
import org.jsola.contract.dto.*;
import org.jsola.contract.entity.AccountDO;
import org.jsola.contract.entity.CategoryDO;
import org.jsola.contract.entity.ContractConfigSiteDO;
import org.jsola.contract.entity.ContractDO;
import org.jsola.contract.query.ContractExportQuery;
import org.jsola.contract.query.ContractQuery;
import org.jsola.contract.query.SealPositionQuery;
import org.jsola.contract.service.*;
import org.jsola.contract.vo.*;
import org.jsola.core.Page;
import org.jsola.core.entity.BaseDO;
import org.jsola.exception.ParamException;
import org.jsola.orm.filter.Order;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.mapperhelper.EntityHelper;

import static org.jsola.contract.constant.ContractConstants.*;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import static org.jsola.contract.constant.ContractConstants.CONTRACT_STATUS_PERSON;
import static org.jsola.contract.constant.ContractConstants.SEAL_POSITION_TYPE_REGULAR;

/**
 * 合同
 *
 * @author JanusMix
 */
@Service("contractContractServiceImpl")
public class ContractServiceImpl implements IContractService {

    @Autowired
    private IContractDAO contractDAO;

    @Autowired
    private ICategoryService categoryService;

    @Autowired
    private IPartySignService partySignService;

    @Autowired
    private IContractVariableService contractVariableService;

    @Autowired
    @Lazy
    private IAppendixService appendixService;

    @Autowired
    private IPersonSignatureService personSignatureService;

    @Autowired
    private ISealPositionService sealPositionService;

    @Autowired
    private ITemplateService templateService;

    @Autowired
    private ISynchronizeContractService synchronizeContractService;

    @Autowired
    private IContractConfigSiteService contractConfigSiteService;

    @Autowired
    private IAccountService accountService;

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public ContractVO save(ContractAddDTO contractAddDTO, TokenUser tokenUser) {
        // 转DO
        ContractDO contractDO = contractAddDTO.to(ContractDO.class);

        // 校验合同编号
        checkContractNo(contractDO.getId(), contractDO.getContractNo(), contractDO.getSubjectId(), tokenUser.getSiteId());

        Long categoryId = contractAddDTO.getCategoryId();
        if (categoryId != null) {
            //有权限分类，使用分类的档案类型
            CategoryDO categoryDO = categoryService.selectDOById(categoryId, tokenUser.getSiteId());
            if (categoryDO != null) {
                contractDO.setFileType(categoryDO.getFileType());
            }
        }
        // 签署编号,当前时间+4位随机吗
        // 字符串形当前时间
        String dateStr = DateKit.getDateStr(DateKit.getToday(), "yyyyMMddHHmm");
        // 6位随机数
        String randomNum = RandomStringUtils.random(6, false, true);
        contractDO.setSignNo(dateStr + randomNum);

        // 保存
        contractDO = save(contractDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return contractDO.to(ContractVO.class);
    }

    /**
     * 校验合同编号
     *
     * @param id         合同id
     * @param contractNo 合同编号
     * @param subjectId  业务id
     * @param siteId     站点
     */
    private void checkContractNo(Long id, String contractNo, String subjectId, String siteId) {
        if (StringUtils.isEmpty(contractNo)) {
            return;
        }
        ContractVO contractVO = findByContractNo(contractNo, subjectId, siteId);
        if (Objects.nonNull(contractVO)) {
            if (id == null || !id.equals(contractVO.getId())) {
                throw new ParamException("合同备注'" + contractNo + "'已存在");
            }
        }
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public List<ContractVO> batchSave(List<ContractAddDTO> contractAddDTOList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(contractAddDTOList)) {
            return null;
        }
        List<ContractDO> contractDOList = contractAddDTOList
                .parallelStream()
                .map(contractAddDTO -> {
                    ContractDO contractDO = contractAddDTO.to(ContractDO.class);
                    contractDO.preInsert(tokenUser.getUserId());
                    contractDO.setSiteId(tokenUser.getSiteId());
                    return contractDO;
                }).collect(Collectors.toList());
        contractDAO.insertListAndSetId(contractDOList);
        return contractDOList
                .parallelStream()
                .map(contractDO -> contractDO.to(ContractVO.class))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int update(ContractUpdateDTO contractUpdateDTO, TokenUser tokenUser) {


        //转DO
        ContractDO contractDO = contractUpdateDTO.to(ContractDO.class);

        ContractDO contractOld = selectDOById(contractDO.getId(), tokenUser.getSiteId());
        if (Objects.isNull(contractOld)) {
            return 0;
        } else if (StringUtils.isEmpty(contractDO.getSubjectId())
                && StringUtils.isNotEmpty(contractOld.getSubjectId())) {
            // 更新非null值,subjectId放上之前的,便于校验
            contractDO.setSubjectId(contractOld.getSubjectId());
        }

        // 校验合同编号
//        checkContractNo(contractDO.getId(), contractDO.getContractNo(), contractDO.getSubjectId(), tokenUser.getSiteId());

        //根据主键更新，只更新非null值
        return updateByIdSelective(contractDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, Long... contractIds) {
        if (contractIds == null || contractIds.length == 0) {
            throw new ParamException("请选择要删除的合同");
        }
        List<Long> ids = Arrays.asList(contractIds);
        // 异步删除合同其他信息
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(() -> {
            // 合同关联模板变量
            contractVariableService.deleteByContractIds(ids, tokenUser);
            // 合同签署方签署记录
            partySignService.deleteByContractIds(ids, tokenUser);
            // 合同个人签名表
            personSignatureService.deleteByContractIds(ids, tokenUser);
            // 合同文件
            appendixService.deleteByContractIds(ids, tokenUser);
        });
        executorService.shutdown();
        // 删除前查看员工是否还有其他未签署合同
        List<ContractDO> contractDOList = selectByIds(ids);
        if (CollectionUtils.isEmpty(contractDOList)) {
            return contractIds.length;
        }
        String subjectId = contractDOList.get(0).getSubjectId();
        List<String> partyBPhoneList = contractDOList.parallelStream()
                .map(ContractDO::getPartyBPhone).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        int deleteByIds = deleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) contractIds);
        // 删除后查看指定手机号还有哪些合同 并同步人员信息
        synchronizeByPhone(partyBPhoneList, subjectId, tokenUser);
        return deleteByIds;
    }

    /**
     * 同步公司下B方合同信息
     *
     * @param phoneList B方手机号
     * @param subjectId 公司Id
     * @param tokenUser 当前用户
     */
    @Async
    public void synchronizeByPhone(List<String> phoneList, String subjectId, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(phoneList)) {
            return;
        }
        Example example = new Example(ContractDO.class);
        example.and()
                .andEqualTo("subjectId", subjectId)
                .andIn("partyBPhone", phoneList);
        List<ContractDO> contractDOList = contractDAO.selectByExample(example);
        Map<String, List<ContractDO>> phoneListMap = new HashMap<>(16);
        if (!CollectionUtils.isEmpty(contractDOList)) {
            // 按手机号分组
            phoneListMap = contractDOList.parallelStream()
                    .collect(Collectors.groupingBy(ContractDO::getPartyBPhone));
        }
        Map<String, List<ContractDO>> map = phoneListMap;
        List<PhoneStatusDTO> phoneStatusDTOList = phoneList.parallelStream().distinct().map(phone -> {
            PhoneStatusDTO phoneStatusDTO = new PhoneStatusDTO();
            phoneStatusDTO.setPhone(phone);
            // 员工的合同信息
            List<ContractDO> contractList = map.get(phone);
            if (CollectionUtils.isEmpty(contractList)) {
                phoneStatusDTO.setStatus(0);
            } else {
                Integer status = contractList.parallelStream().map(ContractDO::getStatus).min(Integer::compareTo).orElse(0);
                phoneStatusDTO.setStatus(status);
            }
            return phoneStatusDTO;
        }).collect(Collectors.toList());
        synchronizeContractService.synchronizeContractStatusByPhone(phoneStatusDTOList, subjectId, tokenUser);
    }


    @Override
    public ContractVO selectById(Long contractId, String siteId) {
        ContractDO contractDO = selectDOById(contractId, siteId);
        if (contractDO == null) {
            return null;
        }
        return contractDO.to(ContractVO.class);
    }

    @Override
    public List<ContractListVO> select(ContractQuery contractQuery, String siteId) {
        ParamException.hasText(contractQuery.getSubjectId(), "请传递合同所属业务Id,例如:公司id");

        List<ContractDO> contractDOList = selectDO(contractQuery, siteId);
        if (CollectionUtils.isEmpty(contractDOList)) {
            return contractDOList == null ? null : new ArrayList<>();
        }
        return contractDOList.stream()
                .map(contractDO -> contractDO.to(ContractListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public List<ContractDO> listNoContent(String subjectId, String partyBAccountId, String siteId) {
        Example example = new Example(ContractDO.class);
        example.and()
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("partyBAccountId", partyBAccountId)
                .andEqualTo("siteId", siteId);
        example.excludeProperties("content");
        return contractDAO.selectByExample(example);
    }

    @Override
    public int selectCount(ContractQuery contractQuery, String siteId) {
        return contractDAO.findCountByQuery(contractQuery, siteId);
    }

    @Override
    public Page<ContractListVO> selectPage(ContractQuery contractQuery, String siteId) {
        ParamException.hasText(contractQuery.getSubjectId(), "请传递合同所属业务Id,例如:公司id");
        //将order参数中的propertyName改为dbName
        List<Order> orders = contractQuery.getOrders();
        if (!CollectionUtils.isEmpty(orders)) {
            orders.forEach(order ->
                    order.setProperty(EntityHelper.getEntityTable(ContractDO.class).getPropertyMap().get(order.getProperty()).getColumn())
            );
        }
        contractQuery.setOrders(orders);

        if (StringUtils.isNotEmpty(contractQuery.getContractNameOrNoOrSignNo())) {
            // 多手机号检索'15854239876,15854239876'
            if (contractQuery.getContractNameOrNoOrSignNo().contains(",")
                    || contractQuery.getContractNameOrNoOrSignNo().contains("，")) {
                contractQuery.setPhones(contractQuery.getContractNameOrNoOrSignNo());
                contractQuery.setContractNameOrNoOrSignNo(null);
            }
        }

        Page<ContractDO> page = contractDAO.findPageByQuery(contractQuery, siteId);
        Page<ContractListVO> resultPage = page.to(ContractListVO.class);
        List<ContractListVO> resultList = resultPage.getEntities();
        //设置合同签署方信息
        for (ContractListVO contractListVO : resultList) {
            contractListVO.setPartySignAccountList(partySignService.selectAccountByContractId(contractListVO.getId(), siteId));
        }
        return resultPage;
    }

    @Override
    public Page<ContractListVO> selectPageNoSubjectId(ContractQuery contractQuery, String siteId) {
        //将order参数中的propertyName改为dbName
        List<Order> orders = contractQuery.getOrders();
        if (!CollectionUtils.isEmpty(orders)) {
            orders.forEach(order ->
                    order.setProperty(EntityHelper.getEntityTable(ContractDO.class).getPropertyMap().get(order.getProperty()).getColumn())
            );
        }
        contractQuery.setOrders(orders);

        if (StringUtils.isNotEmpty(contractQuery.getContractNameOrNoOrSignNo())) {
            // 多手机号检索'15854239876,15854239876'
            if (contractQuery.getContractNameOrNoOrSignNo().contains(",")
                    || contractQuery.getContractNameOrNoOrSignNo().contains("，")) {
                contractQuery.setPhones(contractQuery.getContractNameOrNoOrSignNo());
                contractQuery.setContractNameOrNoOrSignNo(null);
            }
        }

        // 指定成员Id
        if (!CollectionUtils.isEmpty(contractQuery.getMemberIds())) {
            // 查询账户信息(乙方)
            List<AccountDO> accountDOList = accountService.findAccounts(AccountType.PERSON, contractQuery.getMemberIds());
            if (CollectionUtils.isEmpty(accountDOList)) {
                return new Page<>(contractQuery.getPageSize(), contractQuery.getPageNo());
            }
            contractQuery.setPartyBAccountIds(accountDOList.parallelStream().map(BaseDO::getId).collect(Collectors.toList()));
        }

        Page<ContractDO> page = contractDAO.findPageByQuery(contractQuery, siteId);
        Page<ContractListVO> resultPage = page.to(ContractListVO.class);
        List<ContractListVO> resultList = resultPage.getEntities();
        //设置合同签署方信息
        for (ContractListVO contractListVO : resultList) {
            contractListVO.setPartySignAccountList(partySignService.selectAccountByContractId(contractListVO.getId(), siteId));
        }
        return resultPage;
    }

    @Override
    public ContractDO selectDOById(Long contractId, String siteId) {
        return contractDAO.findById(contractId, siteId);
    }

    @Override
    public List<ContractDO> selectByIds(List<Long> contractIds) {
        if (CollectionUtils.isEmpty(contractIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(ContractDO.class);
        example.and().andIn("id", contractIds);
        return contractDAO.selectByExample(example);
    }

    @Override
    public List<ContractDO> selectNoContentByIds(List<Long> contractIds) {
        if (CollectionUtils.isEmpty(contractIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(ContractDO.class);
        example.and().andIn("id", contractIds);
        example.selectProperties("id", "categoryId", "templateId", "contractNo", "signNo",
                "subjectId", "name", "sealType", "contractType", "publishDate",
                "signDate", "endDate", "partyAAccountId", "partyAName", "partyBAccountId",
                "partyBName", "partyBPhone", "price", "status", "dateline",
                "fileType", "needInitAgain", "againContractId", "appIsShow", "siteId",
                "gmtCreate", "createUserId", "gmtModified", "modifiedUserId");
        return contractDAO.selectByExample(example);
    }

    @Override
    public List<ContractDO> selectDO(ContractQuery contractQuery, String siteId) {
        //将order参数中的propertyName改为dbName
        List<Order> orders = contractQuery.getOrders();
        if (!CollectionUtils.isEmpty(orders)) {
            orders.forEach(order ->
                    order.setProperty(EntityHelper.getEntityTable(ContractDO.class).getPropertyMap().get(order.getProperty()).getColumn())
            );
        }
        contractQuery.setOrders(orders);
        return contractDAO.findListByQuery(contractQuery, siteId);
    }

    @Override
    public List<ContractDO> selectNoContentDO(ContractQuery contractQuery, String siteId) {
        //将order参数中的propertyName改为dbName
        List<Order> orders = contractQuery.getOrders();
        if (!CollectionUtils.isEmpty(orders)) {
            orders.forEach(order ->
                    order.setProperty(EntityHelper.getEntityTable(ContractDO.class).getPropertyMap().get(order.getProperty()).getColumn())
            );
        }
        contractQuery.setOrders(orders);
        return contractDAO.findListNoContentByQuery(contractQuery, siteId);
    }

    @Override
    public List<ContractDO> selectByCategoryId(Long categoryId, String siteId) {
        Example example = new Example(ContractDO.class);
        example.and()
                .andEqualTo("categoryId", categoryId)
                .andEqualTo("siteId", siteId);
        return contractDAO.selectByExample(example);
    }

    @Override
    public List<Long> selectCategoryIdBySubjectIds(List<String> subjectIds) {
        if (CollectionUtils.isEmpty(subjectIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(ContractDO.class);
        example.and()
                .andIn("subjectId", subjectIds)
                .andIn("status", Arrays.asList(CONTRACT_STATUS_PERSON, CONTRACT_STATUS_ENTERPRISE));
        example.selectProperties("categoryId");
        List<ContractDO> contractDOList = contractDAO.selectByExample(example);
        return contractDOList.parallelStream().map(ContractDO::getCategoryId).collect(Collectors.toList());
    }

    @Override
    public List<ContractDO> selectAllReadySignContract() {
        Example example = new Example(ContractDO.class);
        example.and()
                .andEqualTo("status", CONTRACT_STATUS_PERSON);
        example.selectProperties("id", "categoryId", "templateId", "contractNo", "signNo",
                "subjectId", "name", "sealType", "contractType", "publishDate",
                "signDate", "endDate", "partyAAccountId", "partyAName", "partyBAccountId",
                "partyBName", "partyBPhone", "price", "status", "dateline",
                "fileType", "needInitAgain", "againContractId", "appIsShow", "siteId",
                "gmtCreate", "createUserId", "gmtModified", "modifiedUserId");
        return contractDAO.selectByExample(example);
    }

    @Override
    public ContractVO findByContractNo(String contractNo, String subjectId, String siteId) {

        Example example = new Example(ContractDO.class);
        example.and()
                .andEqualTo("contractNo", contractNo)
                .andEqualTo("siteId", siteId);

        if (StringUtils.isNotEmpty(subjectId)) {
            example.and().andEqualTo("subjectId", subjectId);
        }
        ContractDO contractDO = contractDAO.selectOneByExample(example);
        if (contractDO == null) {
            return null;
        }
        return contractDO.to(ContractVO.class);
    }

    @Override
    public ContractDO selectByContractNo(String contractNo) {
        Example example = new Example(ContractDO.class);
        example.and().andEqualTo("contractNo", contractNo);
        return contractDAO.selectOneByExample(example);
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int updateContractNoById(Long contractId, String contractNo, TokenUser tokenUser) {
        ContractDO contractDO = selectDOById(contractId, tokenUser.getSiteId());
        ParamException.notNull(contractDO, "要修改的合同不存在或已删除");

        // 修改
        ContractUpdateDTO contractUpdateDTO = new ContractUpdateDTO();
        contractUpdateDTO.setId(contractId);
        contractUpdateDTO.setSubjectId(contractDO.getSubjectId());
        if (StringUtils.isBlank(contractNo)) {
            contractNo = "";
        }
        contractUpdateDTO.setContractNo(contractNo);
        return update(contractUpdateDTO, tokenUser);
    }

    @Override
    public ContractCountVO getContractCount(Integer contractType, String subjectId, TokenUser tokenUser) {
        Example example = new Example(ContractDO.class);
        // 全部合同数量
        example.and()
                .andEqualTo("contractType", contractType)
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("siteId", tokenUser.getSiteId());

        Integer allContractCount = contractDAO.selectCountByExample(example);

        // 待员工签署数量
        example.clear();
        example.and()
                .andEqualTo("status", CONTRACT_STATUS_PERSON)
                .andEqualTo("contractType", contractType)
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("siteId", tokenUser.getSiteId());

        Integer toSignedByEmpCount = contractDAO.selectCountByExample(example);

        // 待公司签署数量
        example.clear();
        example.and()
                .andEqualTo("status", ContractConstants.CONTRACT_STATUS_ENTERPRISE)
                .andEqualTo("contractType", contractType)
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("siteId", tokenUser.getSiteId());

        Integer toSignedByComCount = contractDAO.selectCountByExample(example);

        // 撤销合同数量
        example.clear();
        example.and()
                .andEqualTo("status", ContractConstants.CONTRACT_STATUS_CANCEL)
                .andEqualTo("contractType", contractType)
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("siteId", tokenUser.getSiteId());
        Integer cancelCount = contractDAO.selectCountByExample(example);

        // 已完成签署数量
        example.clear();
        example.and()
                .andEqualTo("status", ContractConstants.CONTRACT_STATUS_FINISH)
                .andEqualTo("contractType", contractType)
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("siteId", tokenUser.getSiteId());

        ContractConfigSiteDO contractConfigSiteDO = contractConfigSiteService.selectBySiteId(tokenUser.getSiteId());
        Integer quotaRemain = null;
        if (contractConfigSiteDO != null) {
            quotaRemain = contractConfigSiteDO.getQuotaRemain();
        }
        Integer signedCompleteCount = contractDAO.selectCountByExample(example);

        // 即将到期数量
        example.clear();
        example.and()
                .andEqualTo("contractType", contractType)
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andCondition("DATEDIFF(end_date,now()) <= 90")
                .andCondition("DATEDIFF(end_date,now()) >= 0");

        Integer immediatelyMaturityCount = contractDAO.selectCountByExample(example);

        // 已到期数量
        example.clear();
        example.and()
                .andEqualTo("contractType", contractType)
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andCondition("DATEDIFF(end_date,now()) < 0");

        Integer alreadyMaturityCount = contractDAO.selectCountByExample(example);

        // 已过期数量（发起了合同 规定了时间签署 员工没有签署的合同数量）
        example.clear();
        example.and()
                .andEqualTo("status", ContractConstants.CONTRACT_STATUS_FAILED)
                .andEqualTo("contractType", contractType)
                .andEqualTo("subjectId", subjectId)
                .andEqualTo("siteId", tokenUser.getSiteId());
        Integer pastCount = contractDAO.selectCountByExample(example);

        ContractCountVO contractCountVO = new ContractCountVO();
        contractCountVO.setImmediatelyMaturityCount(immediatelyMaturityCount);
        contractCountVO.setAlreadyMaturityCount(alreadyMaturityCount);
        contractCountVO.setAllContractCount(allContractCount);
        contractCountVO.setToSignedByEmpCount(toSignedByEmpCount);
        contractCountVO.setToSignedByComCount(toSignedByComCount);
        contractCountVO.setSignedCompleteCount(signedCompleteCount);
        contractCountVO.setCancelCount(cancelCount);
        contractCountVO.setQuotaRemain(quotaRemain);
        contractCountVO.setPastCount(pastCount);
        return contractCountVO;
    }

    @Override
    public ContractCountVO getContractCount(Integer contractType, List<String> subjectIds, TokenUser tokenUser) {
        Example example = new Example(ContractDO.class);
        // 全部合同数量
        example.and()
                .andEqualTo("contractType", contractType)
                .andIn("subjectId", subjectIds)
                .andEqualTo("siteId", tokenUser.getSiteId());

        Integer allContractCount = contractDAO.selectCountByExample(example);
        // 待员工签署数量
        example.clear();
        example.and()
                .andEqualTo("status", CONTRACT_STATUS_PERSON)
                .andEqualTo("contractType", contractType)
                .andIn("subjectId", subjectIds)
                .andEqualTo("siteId", tokenUser.getSiteId());

        Integer toSignedByEmpCount = contractDAO.selectCountByExample(example);
        // 待公司签署数量
        example.clear();
        example.and()
                .andEqualTo("status", ContractConstants.CONTRACT_STATUS_ENTERPRISE)
                .andEqualTo("contractType", contractType)
                .andIn("subjectId", subjectIds)
                .andEqualTo("siteId", tokenUser.getSiteId());

        Integer toSignedByComCount = contractDAO.selectCountByExample(example);
        // 已完成签署数量
        example.clear();
        example.and()
                .andEqualTo("status", ContractConstants.CONTRACT_STATUS_FINISH)
                .andEqualTo("contractType", contractType)
                .andIn("subjectId", subjectIds)
                .andEqualTo("siteId", tokenUser.getSiteId());
        Integer signedCompleteCount = contractDAO.selectCountByExample(example);

        // 剩余额度
        ContractConfigSiteDO contractConfigSiteDO = contractConfigSiteService.selectBySiteId(tokenUser.getSiteId());
        Integer quotaRemain = null;
        if (contractConfigSiteDO != null) {
            quotaRemain = contractConfigSiteDO.getQuotaRemain();
        }

        // 即将到期数量
        example.clear();
        example.and()
                .andEqualTo("contractType", contractType)
                .andIn("subjectId", subjectIds)
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andCondition("DATEDIFF(end_date,now()) <= 90")
                .andCondition("DATEDIFF(end_date,now()) >= 0");
        Integer immediatelyMaturityCount = contractDAO.selectCountByExample(example);

        // 已到期数量
        example.clear();
        example.and()
                .andEqualTo("contractType", contractType)
                .andIn("subjectId", subjectIds)
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andCondition("DATEDIFF(end_date,now()) < 0");
        Integer alreadyMaturityCount = contractDAO.selectCountByExample(example);
        // 返回统计结果
        ContractCountVO contractCountVO = new ContractCountVO();
        contractCountVO.setImmediatelyMaturityCount(immediatelyMaturityCount);
        contractCountVO.setAlreadyMaturityCount(alreadyMaturityCount);
        contractCountVO.setAllContractCount(allContractCount);
        contractCountVO.setToSignedByEmpCount(toSignedByEmpCount);
        contractCountVO.setToSignedByComCount(toSignedByComCount);
        contractCountVO.setSignedCompleteCount(signedCompleteCount);
        contractCountVO.setQuotaRemain(quotaRemain);
        return contractCountVO;
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public void updateAppShowById(Long contractId, Boolean isShow, TokenUser tokenUser) {
        ContractDO contractDO = selectDOById(contractId, tokenUser.getSiteId());
        ParamException.notNull(contractDO, "合同不存在或已删除");
        ParamException.notNull(isShow, "请传递正确的小程序是否展示状态");

        // 修改
        ContractUpdateDTO updateDTO = new ContractUpdateDTO();
        updateDTO.setId(contractDO.getId());
        updateDTO.setAppIsShow(isShow);
        update(updateDTO, tokenUser);
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public void deleteContractAndRelationById(Long contractId, TokenUser tokenUser) {
        ContractDO contractDO = selectDOById(contractId, tokenUser.getSiteId());
        ParamException.notNull(contractDO, "合同不存在或已删除");
        deleteByIds(tokenUser, contractId);
    }

    @Override
    public List<ContractListVO> selectContractList(ContractExportQuery contractExportQuery, TokenUser tokenUser) {


        long startTime = System.currentTimeMillis();
        List<ContractDO> contractDOList = contractDAO.findByQuery(contractExportQuery, tokenUser.getSiteId());
        long endTime = System.currentTimeMillis();
        System.out.println("合同列表查询时间:======" + (endTime - startTime) + "ms");
        List<ContractListVO> contractListVOList = new ArrayList<>();
        if (CollectionUtils.isEmpty(contractDOList)) {
            return contractListVOList;
        }
        contractListVOList = contractDOList.stream()
                .map(contractDO -> contractDO.to(ContractListVO.class))
                .collect(Collectors.toList());
        return contractListVOList;
    }

    @Override
    public Integer saveWordToContract(PdfToContractAddDTO pdfToContractAddDTO, TokenUser tokenUser) {
        // 修改合同模板的content属性为已保存签署位置
        TemplateUpdateDTO templateUpdateDTO = new TemplateUpdateDTO();
        templateUpdateDTO.setId(pdfToContractAddDTO.getTemplateId());
        templateUpdateDTO.setContent("已保存签署位置");
        templateService.update(templateUpdateDTO, tokenUser);
        // 根据合同模板id 查询印章位置表，如果有则修改
        SealPositionQuery sealPositionQuery = new SealPositionQuery();
        sealPositionQuery.setTemplateId(pdfToContractAddDTO.getTemplateId());
        if (CollectionUtils.isEmpty(sealPositionService.select(sealPositionQuery, tokenUser.getSiteId()))) {
            // 保存个人印章位置信息
            SealPositionAddDTO sealPositionAddDTO = new SealPositionAddDTO();
            sealPositionAddDTO.setTemplateId(pdfToContractAddDTO.getTemplateId());
            sealPositionAddDTO.setSealPage(pdfToContractAddDTO.getSealPeoplePage());
            sealPositionAddDTO.setSealPositionX(pdfToContractAddDTO.getSealPeoplePositionX());
            sealPositionAddDTO.setSealPositionY(pdfToContractAddDTO.getSealPeoplePositionY());
            sealPositionAddDTO.setAccountType(AccountType.PERSON.getValue());
            sealPositionAddDTO.setType(SEAL_POSITION_TYPE_REGULAR);
            SealPositionVO sealPositionVO = sealPositionService.save(sealPositionAddDTO, tokenUser);
            if (Objects.isNull(sealPositionVO)) {
                throw new ParamException("个人印章位置信息保存出错，请联系管理员");
            }
            // 保存企业印章位置信息
            sealPositionAddDTO = new SealPositionAddDTO();
            sealPositionAddDTO.setTemplateId(pdfToContractAddDTO.getTemplateId());
            sealPositionAddDTO.setSealPage(pdfToContractAddDTO.getSealCompanyPage());
            sealPositionAddDTO.setSealPositionX(pdfToContractAddDTO.getSealCompanyPositionX());
            sealPositionAddDTO.setSealPositionY(pdfToContractAddDTO.getSealCompanyPositionY());
            sealPositionAddDTO.setAccountType(AccountType.ENTERPRISE.getValue());
            sealPositionAddDTO.setType(SEAL_POSITION_TYPE_REGULAR);
            sealPositionVO = sealPositionService.save(sealPositionAddDTO, tokenUser);
            if (Objects.isNull(sealPositionVO)) {
                throw new ParamException("企业印章位置信息保存出错，请联系管理员");
            }
        } else {
            // 修改合同相关信息（印章位置）
            // 修改个人印章位置信息
            sealPositionQuery = new SealPositionQuery();
            sealPositionQuery.setTemplateId(pdfToContractAddDTO.getTemplateId());
            sealPositionQuery.setAccountType(AccountType.PERSON.getValue());
            List<SealPositionListVO> sealPositionListVOList = sealPositionService.select(sealPositionQuery, tokenUser.getSiteId());
            SealPositionUpdateDTO sealPositionUpdateDTO = new SealPositionUpdateDTO();
            sealPositionUpdateDTO.setId(sealPositionListVOList.get(0).getId());
            sealPositionUpdateDTO.setSealPage(pdfToContractAddDTO.getSealPeoplePage());
            sealPositionUpdateDTO.setSealPositionX(pdfToContractAddDTO.getSealPeoplePositionX());
            sealPositionUpdateDTO.setSealPositionY(pdfToContractAddDTO.getSealPeoplePositionY());
            int countOne = sealPositionService.update(sealPositionUpdateDTO, tokenUser);
            if (countOne < 1) {
                throw new ParamException("个人印章位置信息修改出错，请联系管理员");
            }
            // 修改企业印章位置信息
            sealPositionQuery = new SealPositionQuery();
            sealPositionQuery.setTemplateId(pdfToContractAddDTO.getTemplateId());
            sealPositionQuery.setAccountType(AccountType.ENTERPRISE.getValue());
            sealPositionListVOList = sealPositionService.select(sealPositionQuery, tokenUser.getSiteId());
            sealPositionUpdateDTO = new SealPositionUpdateDTO();
            sealPositionUpdateDTO.setId(sealPositionListVOList.get(0).getId());
            sealPositionUpdateDTO.setSealPage(pdfToContractAddDTO.getSealCompanyPage());
            sealPositionUpdateDTO.setSealPositionX(pdfToContractAddDTO.getSealCompanyPositionX());
            sealPositionUpdateDTO.setSealPositionY(pdfToContractAddDTO.getSealCompanyPositionY());
            int countTwo = sealPositionService.update(sealPositionUpdateDTO, tokenUser);
            if (countTwo < 1) {
                throw new ParamException("企业印章位置信息保存出错，请联系管理员");
            }
        }
        return 1;
    }

    @Override
    public List<ContractDO> listAllNoExpireContract() {
        Example example = new Example(ContractDO.class);
        // 查询结束时间不为空,且在当前时间之后的合同
        example.and()
                .andIsNotNull("endDate")
                .andGreaterThan("endDate", DateKit8.getCurrentDay(DateKit8.DATE));
        example.excludeProperties("content");
        return contractDAO.selectByExample(example);
    }

    @Override
    public List<ContractDO> selectBySubjectId(String subjectId) {
        Example example = new Example(ContractDO.class);
        example.and()
                .andEqualTo("status", CONTRACT_STATUS_FINISH)
                .andEqualTo("subjectId", subjectId);
        return contractDAO.selectByExample(example);
    }

    @Override
    public int selectCountByNameStart(String name, String partyBAccountId, Long notContractId) {
        Example example = new Example(ContractDO.class);
        example.and()
                .andEqualTo("partyBAccountId", partyBAccountId)
                .andLike("name", name + "%");
        if (notContractId != null) {
            example.and().andNotEqualTo("id", notContractId);
        }
        return contractDAO.selectCountByExample(example);
    }

    @Override
    public List<ContractDO> selectBySiteIdAndDate(String siteId, Date startDate, Date endDate, List<String> subjectIds) {
        Example example = new Example(ContractDO.class);
        example.and()
                .andBetween("gmtCreate", startDate, endDate)
                .andEqualTo("siteId", siteId);
        if (!CollectionUtils.isEmpty(subjectIds)) {
            example.and().andIn("subjectId", subjectIds);
        }
        example.selectProperties("gmtCreate");
        return contractDAO.selectByExample(example);
    }
}




